package com.guosen.zebra.framework.starter.idm.ldap.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.guosen.zebra.framework.starter.idm.ldap.constants.IdmLdapAttributes;
import com.guosen.zebra.framework.starter.idm.ldap.enums.IdmLdapRspCode;
import com.guosen.zebra.framework.starter.idm.ldap.model.dept.IdmDeptListRsp;
import com.guosen.zebra.framework.starter.idm.ldap.model.dept.IdmLdapDept;
import com.guosen.zebra.framework.starter.idm.ldap.model.person.IdmLdapPerson;
import com.guosen.zebra.framework.starter.idm.ldap.model.person.IdmPersonListRsp;
import com.guosen.zebra.framework.starter.idm.ldap.properties.IdmLdapProperties;
import com.guosen.zebra.framework.starter.idm.ldap.query.IdmLdapPersonQuery;
import com.guosen.zebra.framework.starter.idm.ldap.service.IdmLdapExecuteService;
import com.guosen.zebra.framework.starter.idm.ldap.service.IdmLdapService;
import com.guosen.zebra.framework.starter.idm.ldap.utils.IdmLdapJsonUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.guosen.zebra.framework.starter.idm.ldap.constants.IdmLdapQuery.*;

/**
 * IDM信息服务实现
 */
@Slf4j
public class IdmLdapServiceImpl implements IdmLdapService {

    private IdmLdapProperties idmLdapProperties;

    private IdmLdapExecuteService idmLdapExecuteService;

    public IdmLdapServiceImpl(IdmLdapProperties idmLdapProperties, IdmLdapExecuteService idmLdapExecuteService) {
        this.idmLdapProperties = idmLdapProperties;
        this.idmLdapExecuteService = idmLdapExecuteService;
    }

    @Override
    public IdmDeptListRsp getLdapDeptList() {
       List<IdmLdapDept> result;
        try {
            String base = idmLdapProperties.getDeptDefaultBase();
            String filter = DEPT_DEFAULT_FILTER;
            log.info("[idm ldap] getDeptList base = {}, filter = {}", base, filter);
            List<Map<String, String>> list = idmLdapExecuteService.consumeServiceWithCustomConfiguration(base, filter,
                    IdmLdapAttributes.DEPT_COLUMNS);
            result = IdmLdapJsonUtil.getObjectMapper().convertValue(list, new TypeReference<List<IdmLdapDept>>() {
            });
            log.info("[idm ldap] getDeptList success size={}", result.size());
            return new IdmDeptListRsp(IdmLdapRspCode.SUCCESS, result);
        } catch (Exception e) {
            log.error("[idm ldap] getLdapDeptList fail, error message: {}", e.getMessage(), e);
            return new IdmDeptListRsp(IdmLdapRspCode.FAILED.getCode(),
                    "查询部门信息失败！失败原因：" + e.getMessage(),null);
        }
    }


    @Override
    public IdmPersonListRsp getLdapPersonList() {
        return getLdapPersonList(idmLdapProperties.getPersonDefaultBase(), idmLdapProperties.getPersonDefaultFilter());
    }

    @Override
    public IdmPersonListRsp getLdapPersonListWithConditions(IdmLdapPersonQuery query) {
        String ldapPersonFilter = getLdapPersonFilter(query);
        return getLdapPersonList(idmLdapProperties.getPersonDefaultBase(), ldapPersonFilter);
    }

    private IdmPersonListRsp getLdapPersonList(String base, String filter) {
        List<IdmLdapPerson> result;
        try {
            log.info("[idm ldap] getPersonList, base = {}, filter = {}", base, filter);
            List<Map<String, String>> list = idmLdapExecuteService.consumeServiceWithCustomConfiguration(base, filter,
                    IdmLdapAttributes.PERSON_COLUMNS);
            result = IdmLdapJsonUtil.getObjectMapper().convertValue(list, new TypeReference<List<IdmLdapPerson>>() {
            });
            log.info("[idm ldap] getPersonList success size={}", result.size());
            return new IdmPersonListRsp(IdmLdapRspCode.SUCCESS, result);
        } catch (Exception e) {
            log.error("[idm ldap] getPersonList fail, error message: {}", e.getMessage(), e);
            return new IdmPersonListRsp(IdmLdapRspCode.FAILED.getCode(),
                    "查询员工信息失败！失败原因：" + e.getMessage(),null);
        }
    }

    private String getLdapPersonFilter(IdmLdapPersonQuery query) {
        String smartStatusCondition = getSmartStatusCondition(query);
        String smartTypeCondition = getSmartTypeCondition(query);
        return String.format(idmLdapProperties.getPersonFilterTemplate(), smartStatusCondition, smartTypeCondition);
    }

    private String getSmartStatusCondition(IdmLdapPersonQuery query) {
        if (query.getSmartStatuses() != null && !query.getSmartStatuses().isEmpty()) {
            return buildOrConditions(query.getSmartStatuses(), SMART_STATUS_PREFIX);
        } else {
            return PERSON_STATUS_EXISTS;
        }
    }

    private String getSmartTypeCondition(IdmLdapPersonQuery query) {
        if (query.getSmartTypes() != null && !query.getSmartTypes().isEmpty()) {
            return buildOrConditions(query.getSmartTypes(), SMART_TYPE_PREFIX);
        } else {
            return PERSON_TYPE_EXISTS;
        }
    }

    private String buildOrConditions(List<String> list, String prefix) {
        String condition = list.stream().map(type -> wrapInParentheses(prefix + type)).collect(Collectors.joining());
        return onlyOneElem(list) ? condition :wrapInParentheses(OR + condition);
    }

    private String wrapInParentheses(String condition) { return "(" + condition + ")"; }

    private boolean onlyOneElem(List list) { return list.size() == 1; }
}
